import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * @author LENOVO
 * 给定一个候选人编号的集合 candidates 和一个目标数 target ，找出 candidates 中所有可以使数字和为 target 的组合。
 *
 * candidates 中的每个数字在每个组合中只能使用 一次 。
 *
 * 注意：解集不能包含重复的组合。
 *
 *
 *
 * 示例 1:
 *
 * 输入: candidates = [10,1,2,7,6,1,5], target = 8,
 * 输出:
 * [
 * [1,1,6],
 * [1,2,5],
 * [1,7],
 * [2,6]
 * ]
 * 示例 2:
 *
 * 输入: candidates = [2,5,2,1,2], target = 5,
 * 输出:
 * [
 * [1,2,2],
 * [5]
 * ]
 */
public class Test40 {

    HashSet<List<Integer>> re =new HashSet<>();
    List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates); // 先对候选数组排序
        dfs(new ArrayList<>(), candidates, target, 0);
        return res;
    }

    private void dfs(List<Integer> path, int[] candidates, int target, int start) {
        if (target == 0) {
            if (re.add(new ArrayList<>(path))){
                res.add(new ArrayList<>(path)); // 找到一个符合条件的组合
            }

            return;
        }

        for (int i = start; i < candidates.length && candidates[i] <= target; i++) {
            path.add(candidates[i]);
            dfs(path, candidates, target - candidates[i], i); // 继续向下搜索
            path.remove(path.size() - 1); // 回溯，移除最后一个元素
        }
    }
    public static void main(String[] args) {
        Test40 combinationSum = new Test40();
        int[] candidates = {2, 2, 2, 3, 6, 7};
        int target = 5;
        List<List<Integer>> result = combinationSum.combinationSum(candidates, target);
        System.out.println(result);
    }
}
